#include "BleDangbei.h"
#include <WiFi.h>

static const char *bundAddrFileKey = "/dangbei.addr";
static BleDangbei *_instance = NULL;

void onSwitchCommand(bool state, HASwitch *sender)
{
    Serial.printf("command is:%d\n", state);
    if (_instance == NULL)
        return;
    sender->setState(state); // report state back to the Home Assistant
    _instance->updateSyncAt();
    if (state)
    {
        _instance->wakeup();
    }
    else
    {
        _instance->shutdown();
    }
}

BleDangbei::BleDangbei(HADevice &device, std::string deviceName, std::string deviceManufacturer, uint8_t batteryLevel)
    : fileHelper(LittleFS), BleBasic(device), BleKeyboard(deviceName, deviceManufacturer, batteryLevel)
{
    _instance = this;
    static const uint8_t dbHidReportDescriptor[] = {
        // 声明为static防止局部对象被销毁
        0x05,
        0x0c,
        0x09,
        0x01,
        0xa1,
        0x01,
        0x85,
        0x01,
        0x19,
        0x00,
        0x2a,
        0x9c,
        0x02,
        0x15,
        0x00,
        0x26,
        0x9c,
        0x02,
        0x95,
        0x01,
        0x75,
        0x10,
        0x81,
        0x00,
        0x09,
        0x02,
        0xa1,
        0x02,
        0x05,
        0x09,
        0x19,
        0x01,
        0x29,
        0x0a,
        0x15,
        0x01,
        0x25,
        0x0a,
        0x95,
        0x01,
        0x75,
        0x08,
        0x81,
        0x40,
        0xc0,
        0xc0,
        0x06,
        0x01,
        0xff,
        0x09,
        0x01,
        0xa1,
        0x02,
        0x85,
        0x05,
        0x09,
        0x14,
        0x75,
        0x08,
        0x95,
        0x14,
        0x15,
        0x80,
        0x25,
        0x7f,
        0x81,
        0x22,
        0x85,
        0x04,
        0x09,
        0x04,
        0x75,
        0x08,
        0x95,
        0x01,
        0x91,
        0x02,
        0xc0,
        0x05,
        0x01,
        0x09,
        0x06,
        0xa1,
        0x01,
        0x85,
        0x0a,
        0x75,
        0x01,
        0x95,
        0x08,
        0x05,
        0x07,
        0x19,
        0xe0,
        0x29,
        0xe7,
        0x15,
        0x00,
        0x25,
        0x01,
        0x81,
        0x02,
        0x95,
        0x01,
        0x75,
        0x08,
        0x81,
        0x01,
        0x95,
        0x05,
        0x75,
        0x01,
        0x05,
        0x08,
        0x19,
        0x01,
        0x29,
        0x05,
        0x91,
        0x02,
        0x95,
        0x01,
        0x75,
        0x03,
        0x91,
        0x01,
        0x95,
        0x06,
        0x75,
        0x08,
        0x15,
        0x00,
        0x26,
        0xff,
        0x00,
        0x05,
        0x07,
        0x19,
        0x00,
        0x29,
        0xff,
        0x81,
        0x00,
        0xc0,
    };
    // 断开连接后不自动重连
    advertiseOnDisconnect = false;
    set_vendor_id(0x2b54);
    set_product_id(0x1600);
    set_version(0x0000);
    set_report_id(0x0a);
    set_report_map((uint8_t *)dbHidReportDescriptor, sizeof(dbHidReportDescriptor));
}

void advise(NimBLEAdvertising *pAdv)
{
    Serial.println("dangbei advise");
    pAdv->stop();
    pAdv->setManufacturerData(""); // 清空数据
    pAdv->start(120);
}

void BleDangbei::updateSyncAt() {
    _lastSyncAt = millis();
}

void BleDangbei::wakeup()
{
    // 发送特殊广播报文唤起投影仪
    if (advertising == NULL)
    {
        return;
    }
    advertising->stop();
    uint8_t buffer[6] = {0};
    size_t size = fileHelper.readFile(bundAddrFileKey, buffer);
    Serial.printf("dangbei wakeup: %d\n", size);
    if (size > 0)
    {
        Serial.println("dangbei bonded addr is:");
        Serial.println(NimBLEAddress(buffer).toString().c_str());
        wakeTimes++;
        char manufacturerData[] = {0x46, 0x00, wakeTimes, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], 0xff, 0xff, 0xff, 0xff};
        advertising->setManufacturerData(std::string(manufacturerData, sizeof(manufacturerData)));
    }
    advertising->start(5, advise); // 发起5秒的广播报文
}

void BleDangbei::shutdown()
{
    write(0x66 + 136);
    delay(500);
    releaseAll();
}

void BleDangbei::onConnect(BLEServer *pServer)
{
    BleKeyboard::onConnect(pServer);
    if (powerSwitch != NULL)
    {
        powerSwitch->setState(true);
    }
}

void BleDangbei::onDisconnect(BLEServer *pServer)
{
    BleKeyboard::onDisconnect(pServer);
    if (powerSwitch != NULL)
    {
        powerSwitch->setState(false);
    }
}

void BleDangbei::onAuthenticationComplete(ble_gap_conn_desc *desc)
{
    bool ret = fileHelper.writeRawFile(bundAddrFileKey, desc->peer_ota_addr.val, sizeof(desc->peer_ota_addr.val));
    Serial.printf("dangbei bonded: %d\n", ret);
}

void BleDangbei::initDevice()
{
    _device.setName(deviceName.c_str());
    _device.setManufacturer(deviceManufacturer.c_str());
    _device.setSoftwareVersion("1.0.0");
    powerSwitch = new HASwitch("pio_dangbei_switch_power");
    powerSwitch->setIcon("mdi:lightbulb");
    powerSwitch->setName("电源");
    powerSwitch->onCommand(onSwitchCommand);
}

// 每15秒同步下状态
void BleDangbei::sync()
{
    if (_lastSyncAt > 0 &&
            (millis() - _lastSyncAt) < SyncInterval) {
        return;
    }
    _lastSyncAt = millis();
    if (powerSwitch != NULL && powerSwitch->getCurrentState() != isConnected())
    {
        powerSwitch->setState(isConnected());
    }
}

BleDangbei::~BleDangbei()
{
    delete powerSwitch;
}
